package mars.io.formatters

import mars.ns.core.Node
import mars.ns.stat.Statistics
import mars.ns.stat.DataRecord
import scala.xml.PrettyPrinter
import java.lang.reflect.ParameterizedType
import scala.xml.XML
import scala.xml.Elem

class StatsXMLFormatter extends Formatter[Statistics[Node]]{
    
	val xmlPrettyPrinter = new PrettyPrinter(Int.MaxValue, 4)
    
	def format(stats: Statistics[Node]): String = {
	    var s = <statistics interval={ stats.getGatheringInterval.toString }> {
            for ((iteration: Int, iterationData: List[DataRecord[_]]) <- stats.getGatheredData) yield {
                <iterationData iteration={ iteration.toString } > {
                    for (data: Any <- iterationData) yield {
                        data match {
                            case dr: DataRecord[t] =>
                                val serialized = (new SerializedFormatter[t]).format(dr.value)
                        		<dataRecord key={ dr.key } class={ dr.value.getClass.getName }>{ serialized }</dataRecord>
                            case _ => //continue
                        }
                    }
                }</iterationData>
            }
        }</statistics>;
	    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + s.toString//xmlPrettyPrinter.format(s)
	}

    def fromString(str: String): Statistics[Node] = {
		val root: Elem = XML.loadString(str)
        val iterations: scala.xml.NodeSeq = root \ "iterationData"
        
        val interval = (root \ "@interval").text.toInt
        var actualIterations: List[(Int, List[DataRecord[_]])] = Nil

        for (iterationData <- iterations) {
        	val iteration = (iterationData \ "@iteration").text.toInt        	
        	val dataRecords = iterationData \ "dataRecord"
        	
        	var actualDataRecords: List[DataRecord[_]] = Nil
        	
        	for(dataRecord <- dataRecords) {
        		val key = (dataRecord \ "@key").text
        		val clazz = Class.forName((dataRecord \ "@class").text) 
        		val value = dataRecord.text.trim
        		clazz match {
        		  case c: Class[t] => 
        		    			val actualValue = (new SerializedFormatter[t]).fromString(value)        		
        		  				val actualDataRecord = new DataRecord[t](key, actualValue)
        		  				actualDataRecords ::= actualDataRecord
        		  case _ => //continue
        		}  		
        	}

            actualIterations ::= (interval, actualDataRecords)      
        }
        
		return new Statistics(interval, actualIterations)
    }

    def validFormat(str: String): Boolean = {
		val schema = this.getClass().getResource("/mars/io/formatters/statistics.xsd")
        return XMLValidator.isValid(str, schema)
    }
}